//
//  ViewController.m
//  opengl_practice
//
//  Created by 3irobot2020 on 2022/3/15.
//

#import "ViewController.h"
#import "RWTVertex.h" //定义了顶点类型
#import "RWTBaseEffect.h"//用于编译glsl
@interface ViewController ()

@end

@implementation ViewController{
    GLuint _vertexBuffer;//顶点数据
    GLuint _indexBuffer; //索引数据
    RWTBaseEffect *_shader;//着色器
    GLsizei _indexCount; //索引数量
}


//使用GL_ARRAY_BUFFER方式绘制(ordered方式)绘制三角形
-(void)setupVertexBufferOld {
    
    //顶点数据初始化方法1
//    const static RWTVertex vertices[] = {
//        {{-1.0, -1.0, 1}},//为何会中间会有两个大括号，因为第一层是代表点信息，按照定义，点信息后面试颜色信息，这里没有初始话，所以第二个大括号是标识一个完整的vertex ，第三层大括号表示，这个是一个结构体数组
//        {{1.0, -1.0, 0}},
//        {{0, 0, 0}}
//    };

    //顶点数据初始化方法2
    //这里定义了一个结构体数组，c语言的结构体数组用大括号 结构体里虽然定义了(Position、Color)两个属性，可以只初始化一个属性，这里初始化的是position
    const static RWTVertex vertices[] = {
        {-1.0, -1.0, 1},
        {1.0, -1.0, 0},
        {0, 0, 0}
    };
    
    /* p vertices
     
     (const RWTVertex [3]) $3 = {
       [0] = {
         Position = ([0] = -1, [1] = -1, [2] = 1)
         Color = (0, 0, 0, 0)
       }
       [1] = {
         Position = ([0] = 1, [1] = -1, [2] = 0)
         Color = (0, 0, 0, 0)
       }
       [2] = {
         Position = ([0] = 0, [1] = 0, [2] = 0)
         Color = (0, 0, 0, 0)
       }
     }
     */
    

    
    
    
    //1在GPU生成 顶点缓冲区 glGenBuffers(GLsizei:个数。GLuint*  缓冲区地址)
    glGenBuffers(1, &_vertexBuffer);
    //绑定缓冲区glBindBuffer(GLenum 缓冲区类型, GLuint 缓冲区id)
    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
    //点cpu定义的顶点缓冲区传给gpu glBufferData(GLenum 缓冲区类型, GLsizeiptr 缓冲区大小, const GLvoid * 顶点数据, GLenum 缓冲区数据的作用，这里为绘制)
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    
}
//使用GL_ELEMENT_ARRAY_BUFFER方式绘制（Indexed方式）绘制带渐变色的四方形
-(void)setupVertexBuffer {
    
    
    
    /*
     
     V2--------|V1
     |*        |
     |  *      |
     |    *    |
     |       * |
   V3|---------| V0
     
     逆时针有两个三角形
     V0、V1、V2
     V2、V3、V0
     
     V0(1,-1)
     V1(1,1)
     V2(-1,1)
     V3(-1,-1)
     */
    
    
//顶点坐标，从V0开始
    const static RWTVertex vertices[] = {
        {{1.0, -1.0, 1},{1,0,0,1}},//V0 red
        {{1.0, 1.0, 0},{0,1,0,1}},// V1 green
        {{-1.0,1.0, 0},{0,0,1,1}},// v2 blue
        {{-1.0,-1.0, 0},{0,0,0,0}}// v3 black
    };
    //索引
    const static GLubyte indices[] = {
        0, 1, 2,
        2, 3, 0
    };
    
    _indexCount = sizeof(indices) / sizeof(indices[0]);
    
    

    
    
    //生成顶点缓冲区
    //1在GPU生成 顶点缓冲区 glGenBuffers(GLsizei:个数。GLuint*  缓冲区地址)
    glGenBuffers(1, &_vertexBuffer);
    //绑定缓冲区glBindBuffer(GLenum 缓冲区类型, GLuint 缓冲区id)
    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
    //点cpu定义的顶点缓冲区传给gpu glBufferData(GLenum 缓冲区类型, GLsizeiptr 缓冲区大小, const GLvoid * 顶点数据, GLenum 缓冲区数据的作用，这里为绘制)
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    
    
    //生成索引缓冲区
    glGenBuffers(1, &_indexBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    
    
    
}

-(void)setupShader {
    //使用顶点着色器，片元着色器编译
    _shader = [[RWTBaseEffect alloc] initWithVertexShader:@"RWTSimpleVertex.glsl" fragmentShader:@"RWTSimpleFragment.glsl"];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    GLKView * view = (GLKView *)self.view;
    view.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];

    
    //设置上下文：I need to set the context OpenGl context and the way you do that is EAGLContext set current context
    // that way all of the rest of these conmmands for setting up the shader and the setup vertex buffer will be using this same context for the view
    [EAGLContext setCurrentContext:view.context];
    //初始化着色器
    [self setupShader];
    //初始化顶点缓冲数据
    [self setupVertexBuffer];
    

}

-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
    glClearColor(0, 104.0/255.0, 55.0/255.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);
    
    //准备绘制
    [_shader prepareToDraw];
    
    
    //需要激活顶点缓冲数组， glEnableVertexAttribArray(GLuint 缓冲区标识，一般是自己定义的)
    glEnableVertexAttribArray(RWTVertexAttribPosition);
    //顶点缓冲数据的定义规则
    /**
     glVertexAttribPointer(
        GLuint indx,  缓冲区标识
        GLint size,  一个顶点数据长度（一般为 x,y,z 三个坐标组成，长度为3）
        GLenum type, 顶点坐标数据类型 一般为 float
        GLboolean normalized, （whether the value should be normalized ,this is only applies if you are passing in  interger parameters and
        maybe you would like to work with them in the range of 0 to 255 and you would rather work with thme in that and then have opengl move them
       into the 0 to 1 float range .because that our true OpenGL would convert the 0 to 255 fange to the 0 to 1 range but we don't need that I mean these
       are just floats so we don't need that so just set that to be false）
        GLsizei stride, you think of the stride is how big is the stucture in which you're storing this Vertex Infomation so that's very clear we just do size of our
          RWTVertex
        const GLvoid *ptr    where is the offset inside the array at which it can find  these values that you're talking about these 3 floats so we know it's the
            first thing in the array and I could just put 0 there but I'm going to show you a little trick that makes this a little bit nicer there's  a keyword and C
     called offset of and you give a structure like RWTVertex and then a item inside the structure like in this postion and it will calculate dynamicaly the offseet
     so reture zero for us here the reson is better to do it this way is because we're not if we move to somewhere else later when I break the code and of course
     to give this the clould be happy I have to cast this to a GL void start
     )
     */
    glVertexAttribPointer(RWTVertexAttribPosition, 3, GL_FLOAT, false, sizeof(RWTVertex), (const GLvoid *)offsetof(RWTVertex, Position));
    
    //激活颜色缓冲区
    glEnableVertexAttribArray(RWTVertexAttribColor);
    glVertexAttribPointer(RWTVertexAttribColor, 4, GL_FLOAT, false, sizeof(RWTVertex), (const GLvoid *)offsetof(RWTVertex, Color));
    
    //绑定顶点缓冲区
    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
    //绑定索引缓冲区
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
    //开始绘制 glDrawArrays(GLenum 绘制类型（点、线、三角形）, GLint 顶点起始下标, GLsizei 顶点个数)
//    glDrawArrays(GL_TRIANGLES, 0, 3);
    //使用索引缓冲绘制
    /*
     glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
     GLenum mode 绘制类型
     GLsizei count  索引个数
     GLenum type    索引数据类型
     const GLvoid *indices  索引起始位置
     */
    /*
     we want to use DL triangles ange and the index count will be recorded earlier we're using unsigned bytes for the indices and we don't want to skip anything so we start from 0 and this it,
     */
    glDrawElements(GL_TRIANGLES, _indexCount, GL_UNSIGNED_BYTE, 0);
    //需要清除顶点缓冲数组， glDisableVertexAttribArray(GLuint 缓冲区标识，一般是自己定义的)
    glDisableVertexAttribArray(RWTVertexAttribPosition);
    //需要清除颜色缓冲数组
    glDisableVertexAttribArray(RWTVertexAttribColor);

}

@end
